/* ------------------------------------------------------------------------*
 *
 * ------------------------------------------------------------------------*/
#include "com_def.h"

/*****************************************************************************//*!
* st check
*****************************************************************************/
uint8_t com_idle_check(com_obj_type *com)
{
  if (com->snd_st != COM_TX_IDLE)
    return 0;
  if (com->rcv_st != COM_RX_IDLE)
    return 0;
  return 1;
}

/*****************************************************************************//*!
* wait for idle
*****************************************************************************/
int16_t com_wait_for_idle(com_obj_type *com, uint16_t time_out)
{

  time_out /= 10;

  while (time_out--)
  {
    if (!com_idle_check(com))
    {
      com_ext_wait(10);
    }
    else
    {
      break;
    }
  }

  return time_out;
}

/*****************************************************************************//*!
* master mode en
*****************************************************************************/
void com_master_mode_en(com_obj_type *com)
{
  com->b_master_mode = 1;
}

/*****************************************************************************//*!
* master mode dis
*****************************************************************************/
void com_master_mode_dis(com_obj_type *com)
{
  com->b_master_mode = 0;
}


/*****************************************************************************//*!
* master mode dis
*****************************************************************************/
void com_end_time_set(com_obj_type *com, uint16_t sv)
{
  com->rcv_end_time_sv = sv;
}


/*****************************************************************************//*!
* master mode dis
*****************************************************************************/
void com_wait_time_set(com_obj_type *com, uint16_t sv)
{
  com->master_wait_time_sv = sv;
}


/*****************************************************************************//*!
* send dat in cycle mode
*****************************************************************************/
#define com_cycle_snd_byte_add() \
  cnt = 3;                      \
  do{                           \
    uint16_t now, next;         \
    now = com->index_tx_fill;   \
    next = now + 1;             \
    if (next >= com->tx_buff_size)  \
      next = 0;                     \
    if (next != com->index_tx_send) \
    {                               \
      com->tx_buff[now] = ch;       \
      com->index_tx_fill = next;    \
      break;                        \
    }                               \
    else                            \
    {                               \
      com_ext_wait(2);              \
    }                               \
  } while (cnt--);                  \

void com_cycle_snd_byte(com_obj_type *com, uint8_t ch)
{
  char cnt;

  if (!com->St.bits.cycle_mode)
    return;

  com_cycle_snd_byte_add();
}

/*****************************************************************************//*!
* rcv dat in cycle mode
*****************************************************************************/
int16_t com_cycle_rcv_byte(com_obj_type *com)
{
  int16_t ch;

  if (!com->St.bits.cycle_mode)
    return COM_DAT_NULL;

  if (com->index_rx_get == com->index_rx_rcv)
    return COM_DAT_NULL;

  ch = com->rx_buff[com->index_rx_get++];

  if (com->index_rx_get >= com->rx_buff_size)
    com->index_rx_get = 0;

  return ch;
}

void com_cycle_snd_string(com_obj_type *com, uint8_t * str)
{
  if (!com->St.bits.cycle_mode)
    return;

  while (*str)
  {
    uint8_t ch = *str, cnt;
    
    com_cycle_snd_byte_add();
  }
}

void com_cycle_snd_data(com_obj_type *com, uint8_t * dat, uint16_t len)
{
  if (!com->St.bits.cycle_mode)
    return;

  while (len--)
  {
    uint8_t ch = *dat++, cnt;
    
    com_cycle_snd_byte_add();
  }
}

/*****************************************************************************//*!
* rcv dat in cycle mode
*****************************************************************************/
uint16_t com_cycle_rcv_multi(com_obj_type *com, uint8_t * dat, uint16_t buff_size)
{
  uint16_t len = 0;

  if (!com->St.bits.cycle_mode)
    return 0;

  while (com->index_rx_get != com->index_rx_rcv)
  {
    *dat++ = com->rx_buff[com->index_rx_get++];

    if (com->index_rx_get >= com->rx_buff_size)
      com->index_rx_get = 0;
    len++;

    if (len >= buff_size)
      break;
  }

  return len;
}

/*****************************************************************************//*!
* rcv dat in cycle mode
*****************************************************************************/
uint16_t com_cycle_rcv_line(com_obj_type *com, uint8_t * dat)
{
  uint16_t len = 0;
  uint16_t index, size, rcv_site;
  uint8_t b_end_found, ch;

  if (!com->St.bits.cycle_mode)
    return 0;

  index = com->index_rx_get;
  size = com->rx_buff_size;
  rcv_site = com->index_rx_rcv;
  b_end_found = 0;

  while (index != rcv_site)
  {
    ch = com->rx_buff[index++];
    *dat++ = ch;
    len++;

    if (index >= size)
      index = 0;

    if ('\n' == ch)
    {
      b_end_found = 1;
      break;
    }
  }

  if (b_end_found)
  {
    com->index_rx_get = index;
  }
  else
  {
    len = 0;
  }

  *dat++ = 0;

  return len;
}

/*****************************************************************************//*!
* rcv dat in cycle mode
*****************************************************************************/
uint16_t com_cycle_rcv_end_4B(com_obj_type *com, uint8_t * dat, uint32_t symbol)
{
  uint16_t len = 0;
  uint16_t index, size, rcv_site;
  uint8_t b_end_found, ch;
  uint32_t snow;

  if (!com->St.bits.cycle_mode)
    return 0;

  index = com->index_rx_get;
  size = com->rx_buff_size;
  rcv_site = com->index_rx_rcv;
  b_end_found = 0;
  snow = 0;

  while (index != rcv_site)
  {
    ch = com->rx_buff[index++];
    *dat++ = ch;
    len++;

    if (index >= size)
      index = 0;

    snow <<= 8;
    snow |= ch;

    if (symbol == snow)
    {
      b_end_found = 1;
      break;
    }
  }

  if (b_end_found)
  {
    com->index_rx_get = index;
  }
  else
  {
    len = 0;
  }

  *dat++ = 0;

  return len;
}

/*****************************************************************************//*!
* rcv dat in cycle mode
*****************************************************************************/
uint16_t com_cycle_rcv_end_2B(com_obj_type *com, uint8_t * dat, uint16_t symbol)
{
  uint16_t len = 0;
  uint16_t index, size, rcv_site;
  uint8_t b_end_found, ch;
  uint16_t snow;

  if (!com->St.bits.cycle_mode)
    return 0;

  index = com->index_rx_get;
  size = com->rx_buff_size;
  rcv_site = com->index_rx_rcv;
  b_end_found = 0;
  snow = 0;

  while (index != rcv_site)
  {
    ch = com->rx_buff[index++];
    *dat++ = ch;
    len++;

    if (index >= size)
      index = 0;

    snow <<= 8;
    snow |= ch;

    if (symbol == snow)
    {
      b_end_found = 1;
      break;
    }
  }

  if (b_end_found)
  {
    com->index_rx_get = index;
  }
  else
  {
    len = 0;
  }

  *dat++ = 0;

  return len;
}

/*****************************************************************************//*!
* rcv dat remain
*****************************************************************************/
uint16_t com_cycle_rcv_remain_amount(com_obj_type *com)
{
  if (com->index_rx_get <= com->index_rx_rcv)
  {
    return (com->index_rx_rcv - com->index_rx_get);
  }
  else
  {
    return (com->index_rx_rcv + com->rx_buff_size - com->index_rx_get);
  }
}

/*****************************************************************************//*!
* snd dat remain
*****************************************************************************/
uint16_t com_cycle_snd_remain_amount(com_obj_type *com)
{
  if (com->index_tx_send <= com->index_tx_fill)
  {
    return (com->index_tx_fill - com->index_tx_send);
  }
  else
  {
    return (com->index_tx_fill + com->tx_buff_size - com->index_tx_send);
  }
}

/*****************************************************************************//*!
* send dat in strint mode
*****************************************************************************/
int16_t com_signal_snd_string(com_obj_type *com, uint8_t *p_dat)
{
  uint8_t send_ok = 0;

  if (com->St.bits.cycle_mode)
    return 1;

  if (com_wait_for_idle(com, 3000))
  {
    com->dat_mode = COM_DAT_STRING;
    com->p_tx = p_dat;
    com->index_tx_send = 0;
    com->index_tx_fill = INT16_MAX;
    com->snd_st = COM_TX_XMIT;
    com->fun->tx_cmd(1);

    send_ok = 1;
  }

  return send_ok;
}

/*****************************************************************************//*!
* send dat in data mode
*****************************************************************************/
int16_t com_signal_snd_data(com_obj_type *com, uint8_t *p_dat, uint16_t len)
{
  uint8_t send_ok = 0;

  if (com->St.bits.cycle_mode)
    return 1;

  if (com_wait_for_idle(com, 3000))
  {
    com->dat_mode = COM_DAT_DATA;
    com->p_tx = p_dat;
    com->index_tx_send = 0;
    com->index_tx_fill = len;
    com->snd_st = COM_TX_XMIT;
    com->fun->tx_cmd(1);

    send_ok = 1;
  }

  return send_ok;
}

/*****************************************************************************//*!
* receive data at signal mode
*****************************************************************************/
int16_t com_signal_rcv_data(com_obj_type *com, uint8_t *p_dat, uint16_t buff_size)
{
  int16_t len = buff_size;
  int16_t cnt = 0;

  if (com->St.bits.cycle_mode)
    return 0;

  while (len--)
  {
    if (com->index_rx_get < com->index_rx_rcv)
    {
      *p_dat++ = com->rx_buff[com->index_rx_get++];
      cnt++;
    }
    else
    {
      break;
    }
  }

  return cnt;
}

/*****************************************************************************//*!
* receive st clr
*****************************************************************************/
int16_t com_rcv_st_clr(com_obj_type *com)
{
  com->index_rx_rcv = 0;
  com->index_rx_get = 0;
  com->St.bits.err_hal = 0;
  com->master_wait_time_cnt = 0;
  com->b_timer_on = 0;
  com->rcv_end_time_cnt = 0;
  com->rcv_end_keep_cnt = 0;
  com->rcv_squence = 0;

  com->rcv_st = COM_RX_IDLE;
  return 0;
}

/*****************************************************************************//*!
* com tx cmd
*****************************************************************************/
void com_tx_cmd(com_obj_type *com, uint8_t en_or_dis)
{
  com->fun->tx_cmd(en_or_dis);
}

/*****************************************************************************//*!
* com rx cmd
*****************************************************************************/
void com_rx_cmd(com_obj_type *com, uint8_t en_or_dis)
{
  com->fun->rx_cmd(en_or_dis);
}

/*****************************************************************************//*!
*RTU��ʱ��������������ʱʱ����
*****************************************************************************/
void com_timer_en(com_obj_type *com) {
  com->b_timer_on = 1;
  com->rcv_end_time_cnt = 0;
}

/*****************************************************************************//*!
*RTU��ʱ���رգ�������ʱʱ����
*****************************************************************************/
void com_timer_dis(com_obj_type *com) {
  com->b_timer_on = 0;
  com->rcv_end_time_cnt = 0;
}

/*****************************************************************************//*!
*��ʱ�����㣬 ����10us���� bitsָʾ��ʱλ���� ����3.5t 11bit��ʽ�� bits=3.5*11
*****************************************************************************/
uint16_t com_timer_cal(uint32_t baud, uint16_t bits, uint16_t min, uint16_t max)
{
  uint32_t res;

  res = (bits * 1000 * 100 + (baud >> 1))/ baud;

  if (res > max)
    res = max;
  if (res < min)
    res = min;

  return (uint16_t)res;
}

/*****************************************************************************/ /*!
* @brief   rtu time end handle .
*****************************************************************************/
void com_timer_run(com_obj_type *com) {
  if (!com->St.bits.run_en)
    return;

  if (com->b_timer_on){
    com->rcv_end_time_cnt++;
    if (com->rcv_end_time_cnt > com->rcv_end_time_sv){
      //disable timer
      com->b_timer_on = 0;
      com->rcv_end_time_cnt = 0;

      if (COM_RX_RCV == com->rcv_st) {
        //receive end
        com->rcv_st = COM_RX_RCVEND;
      }
    }
  }

  //rcv keep time handle
  if (com->b_master_mode)
  {
    if (com->rcv_st == COM_RX_RCVEND)
    {
      if (com->rcv_end_keep_cnt == com->rcv_end_keep_sv)
      {
        //send event
        if (com->os_event_send)
        {
          com->os_event_send(com->os_event_rcv_end);
        }
      }

      if (com->rcv_end_keep_cnt < INT16_MAX)
        com->rcv_end_keep_cnt++;
    }
    else {
      com->rcv_end_keep_cnt = 0;
    }
  }
  else {
    if (com->rcv_st == COM_RX_RCVEND)
    {
      if (com->rcv_end_keep_cnt == 0)
      {
        if (com->os_event_send)
        {
          com->os_event_send(com->os_event_rcv_end);
        }
      }

      if (com->rcv_end_keep_cnt < INT16_MAX)
        com->rcv_end_keep_cnt++;
    }
    else
    {
      com->rcv_end_keep_cnt = 0;
    }
  }

  //time out  //just for master
  if (com->b_master_mode && (com->rcv_st == COM_RX_WAIT))
  {
    com->master_wait_time_cnt++;
    if (com->master_wait_time_cnt > com->master_wait_time_sv){
      com->master_wait_time_cnt = 0;
      com->rcv_st = COM_RX_TIMEOUT;
      //���������¼�
      if (com->os_event_send)
      {
        com->os_event_send(com->os_event_rcv_end);
      }
    }
  }

  //active time cnt
  if ((com->rcv_st == COM_RX_RCV) || (com->snd_st == COM_TX_XMIT))
  {
    if (com->act_time_cnt < UINT16_MAX)
      com->act_time_cnt++;
    if (com->act_time_cnt > com->act_time_max)
      com->act_time_max = com->act_time_cnt;

    com->idle_time_cnt = 0;
  }
  else
  {
    com->act_time_cnt = 0;

    //���м�ʱ
    if ((com->rcv_st == COM_RX_IDLE) && (com->snd_st == COM_TX_IDLE))
    {
      if (com->idle_time_cnt < UINT16_MAX)
        com->idle_time_cnt++;
    }
    else
    {
      com->idle_time_cnt = 0;
    }
  }
}



